package com.xhj.mybatis.executor.resultset;

import com.xhj.mybatis.executor.Executor;
import com.xhj.mybatis.executor.parameter.ParameterHandler;
import com.xhj.mybatis.executor.result.DefaultResultContext;
import com.xhj.mybatis.executor.result.DefaultResultHandler;
import com.xhj.mybatis.mapping.BoundSql;
import com.xhj.mybatis.mapping.MappedStatement;
import com.xhj.mybatis.mapping.ResultMap;
import com.xhj.mybatis.mapping.ResultMapping;
import com.xhj.mybatis.reflection.MetaClass;
import com.xhj.mybatis.reflection.MetaObject;
import com.xhj.mybatis.reflection.ReflectorFactory;
import com.xhj.mybatis.reflection.factory.ObjectFactory;
import com.xhj.mybatis.session.Configuration;
import com.xhj.mybatis.session.ResultContext;
import com.xhj.mybatis.session.ResultHandler;
import com.xhj.mybatis.session.RowBounds;
import com.xhj.mybatis.type.JdbcType;
import com.xhj.mybatis.type.TypeHandler;
import com.xhj.mybatis.type.TypeHandlerRegistry;

import java.lang.reflect.Constructor;
import java.sql.*;
import java.util.*;

/**
 * DefaultResultSetHandler
 *
 * @author XJks
 * @description 默认的结果集处理器
 */
public class DefaultResultSetHandler implements ResultSetHandler {

    /**
     * MyBatis执行器，负责执行SQL语句。todo:目前未使用该字段。
     */
    private final Executor executor;

    /**
     * MyBatis的全局配置对象，包含所有配置信息
     */
    private final Configuration configuration;

    /**
     * 绑定的映射语句信息
     */
    private final MappedStatement mappedStatement;

    /**
     * 分页参数，包含偏移量和限制
     */
    private final RowBounds rowBounds;

    /**
     * 参数处理器，负责为SQL语句设置参数。todo:目前未使用该字段。
     */
    private final ParameterHandler parameterHandler;

    /**
     * 结果处理器，用于处理查询结果（可以自定义结果收集方式）
     */
    private final ResultHandler<?> resultHandler;

    /**
     * 绑定的SQL对象，包含SQL字符串和参数映射。todo:目前未使用该字段。
     */
    private final BoundSql boundSql;

    /**
     * 类型处理器注册表，负责Java类型和JDBC类型之间的转换
     */
    private final TypeHandlerRegistry typeHandlerRegistry;

    /**
     * 对象工厂，用于创建结果对象实例
     */
    private final ObjectFactory objectFactory;

    /**
     * 反射器工厂，用于优化反射操作
     */
    private final ReflectorFactory reflectorFactory;

    /**
     * 自动映射缓存，提升自动映射性能，key为ResultMap和列前缀
     */
    private final Map<String, List<UnMappedColumnAutoMapping>> autoMappingsCache = new HashMap<>();

    /**
     * UnMappedColumnAutoMapping 是一个内部静态类，用于描述自动映射时，数据库列与 Java 属性之间的关系
     */
    private static class UnMappedColumnAutoMapping {
        /**
         * 数据库中的列名
         */
        private final String column;

        /**
         * Java 对象中的属性名
         */
        private final String property;

        /**
         * 用于将数据库类型转换为 Java 类型的类型处理器
         */
        private final TypeHandler<?> typeHandler;

        /**
         * 标记该属性是否为 Java 的基本类型（如 int、boolean 等）
         */
        private final boolean primitive;

        /**
         * 构造方法，初始化自动映射关系
         *
         * @param column      数据库列名
         * @param property    Java 属性名
         * @param typeHandler 类型处理器，用于类型转换
         * @param primitive   是否为基本类型
         */
        public UnMappedColumnAutoMapping(String column, String property, TypeHandler<?> typeHandler, boolean primitive) {
            this.column = column;
            this.property = property;
            this.typeHandler = typeHandler;
            this.primitive = primitive;
        }
    }

    public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement, ParameterHandler parameterHandler, ResultHandler<?> resultHandler, BoundSql boundSql, RowBounds rowBounds) {
        this.executor = executor;
        this.configuration = mappedStatement.getConfiguration();
        this.mappedStatement = mappedStatement;
        this.rowBounds = rowBounds;
        this.parameterHandler = parameterHandler;
        this.resultHandler = resultHandler;
        this.boundSql = boundSql;
        this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        this.objectFactory = configuration.getObjectFactory();
        this.reflectorFactory = configuration.getReflectorFactory();
    }

    /**
     * TODO:
     *  疑问:为啥该方法没有泛型信息，而是直接返回 List<Object>？
     *  回答:
     *      1.因为该方法可能会处理多结果集，每个结果集可能对应不同的 Java 类型，所以只能返回通用的 List<Object>。
     *      2.在处理单结果集是，该方法会调用 collapseSingleResultList 方法，去一层 List 包装，返回具体的 List<T>。
     *
     * @param stmt 执行 SQL 查询后的 Statement 对象
     * @return 查询结果，可能是单个结果集的 List 或多个结果集的 List 列表
     * @throws SQLException SQL 异常
     */
    @Override
    public List<Object> handleResultSets(Statement stmt) throws SQLException {
        // 用于存储所有结果集的结果
        final List<Object> multipleResults = new ArrayList<>();

        // 记录当前处理到第几个结果集
        int resultSetCount = 0;
        // 获取第一个结果集的包装对象
        ResultSetWrapper rsw = getFirstResultSet(stmt);

        // 获取当前语句配置的所有ResultMap（结果映射）
        List<ResultMap> resultMaps = mappedStatement.getResultMaps();
        // 结果映射的数量
        int resultMapCount = resultMaps.size();
        // 校验结果映射数量是否合法
        validateResultMapsCount(rsw, resultMapCount);

        // 处理每一个结果集，直到没有更多结果集或已处理完所有ResultMap
        while (rsw != null && resultMapCount > resultSetCount) {
            // 获取当前要处理的ResultMap
            ResultMap resultMap = resultMaps.get(resultSetCount);
            // 处理当前结果集，将结果存入multipleResults
            handleResultSet(rsw, resultMap, multipleResults, null);
            // 获取下一个结果集
            rsw = getNextResultSet(stmt);
            // 结果集计数加1
            resultSetCount++;
        }

        // todo:源码这里还会处理多结果集逻辑，因为有些 SQL（尤其是存储过程或批量查询）可以返回多个结果集（ResultSet）。这里默认不处理该逻辑，只处理单结果集。

        // 如果只有一个结果集，直接返回其结果，否则返回所有结果的列表
        return collapseSingleResultList(multipleResults);
    }

    /**
     * 获取第一个结果集的包装对象。
     * 某些JDBC驱动（如HSQLDB 2.1）不会在第一次调用时返回结果集，
     * 需要多次调用getMoreResults()才能获取到第一个结果集。
     *
     * @param stmt 执行SQL语句后的Statement对象
     * @return 包装后的ResultSetWrapper对象，如果没有结果集则返回null
     * @throws SQLException SQL异常
     */
    private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
        // 尝试获取第一个结果集
        ResultSet rs = stmt.getResultSet();
        // 如果没有获取到结果集，循环查找
        while (rs == null) {
            // 有些驱动不会直接返回结果集，需要调用getMoreResults()尝试获取下一个结果
            if (stmt.getMoreResults()) {
                // 如果有更多结果，尝试再次获取结果集
                rs = stmt.getResultSet();
            } else {
                // 如果没有更多结果，检查是否还有更新计数
                if (stmt.getUpdateCount() == -1) {
                    // 没有更多结果且没有更新计数，说明没有结果集，跳出循环
                    break;
                }
                // 如果有更新计数，继续循环，直到找到结果集或没有更多结果
            }
        }
        // 如果找到了结果集，则用ResultSetWrapper包装后返回，否则返回null
        return rs != null ? new ResultSetWrapper(rs, configuration) : null;
    }

    /**
     * 获取下一个结果集的包装对象（ResultSetWrapper）。
     * 由于部分 JDBC 驱动实现不规范，这里做了兼容处理，确保能正确获取下一个结果集。
     *
     * @param stmt 执行SQL语句后的Statement对象
     * @return 包装后的ResultSetWrapper对象，如果没有更多结果集则返回null
     */
    private ResultSetWrapper getNextResultSet(Statement stmt) {
        // 兼容一些实现不规范的JDBC驱动，避免抛出异常
        try {
            // 判断当前数据库连接是否支持多结果集
            if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) {
                // 标准JDBC判断是否还有更多结果集的方式
                // stmt.getMoreResults()：尝试移动到下一个结果集，如果没有则返回false
                // stmt.getUpdateCount()：如果没有更多结果和更新计数，返回-1
                if (!(!stmt.getMoreResults() && stmt.getUpdateCount() == -1)) {
                    // 获取下一个结果集
                    ResultSet rs = stmt.getResultSet();
                    if (rs == null) {
                        // 如果没有获取到结果集，递归调用本方法继续尝试
                        return getNextResultSet(stmt);
                    } else {
                        // 如果获取到了结果集，则用ResultSetWrapper包装后返回
                        return new ResultSetWrapper(rs, configuration);
                    }
                }
            }
        } catch (Exception e) {
            // 忽略所有异常，保证即使驱动有问题也不会影响主流程
        }
        // 如果没有更多结果集，返回null
        return null;
    }

    /**
     * 如果结果集只有一个元素且该元素本身是一个 List，则直接返回这个 List；
     * 否则返回原始的 multipleResults 列表。
     * <p>
     * 例如：
     * - 查询返回了一个结果集，且结果集本身是 List，则返回 List。
     * - 查询返回了多个结果集（如存储过程），则返回包含多个 List 的 List。
     *
     * @param multipleResults 存放所有结果集的列表
     * @return 如果只有一个结果集，返回该结果集本身，否则返回所有结果集的列表
     */
    private List<Object> collapseSingleResultList(List<Object> multipleResults) {
        // 如果只有一个结果集，返回第一个元素（强制转换为 List<Object>），否则返回原始列表
        return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults;
    }

    /**
     * 处理单个结果集，将结果集中的数据映射为对象并存储到结果列表或处理器中。
     *
     * @param rsw             包装后的结果集对象
     * @param resultMap       当前要使用的结果映射
     * @param multipleResults 用于存放所有结果集的列表（可能为null，取决于调用场景）
     * @param parentMapping   父级映射（用于嵌套映射时，普通查询为null）
     * @throws SQLException SQL异常
     */
    private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
        try {
            // todo:源码这里利用 parentMapping 判断是否为嵌套映射，进而调用不同的处理方法，当前简化处理，直接默认处理为非嵌套映射。
            if (resultHandler == null) {
                // 如果没有自定义结果处理器，使用默认的 DefaultResultHandler 收集结果
                DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
                // 处理结果集的每一行，将结果存入 defaultResultHandler
                handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
                // 将当前结果集的结果列表添加到 multipleResults
                multipleResults.add(defaultResultHandler.getResultList());
            } else {
                // 如果有自定义结果处理器，直接用它处理每一行
                handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
                /**
                 * TODO:
                 *  相关说明:
                 *      1.源码这里没有将自定义的结果处理器的结果添加到 multipleResults，因为 {@link ResultHandler} 只有 {@link ResultHandler#handleResult} 方法，无法获取结果列表。
                 *      2.如果需要将自定义结果处理器的结果也添加到 multipleResults，则需要自定义一个实现了 ResultHandler 接口的类，且能提供获取结果列表的方法。
                 *      3.综上所述，为了简化处理，为了使用户自定义的结果处理器也能将结果添加到 multipleResults，这里必须要求用户自定义的结果处理器继承自 DefaultResultHandler，以便获取结果列表，从而添加到 multipleResults。
                 */
                multipleResults.add(((DefaultResultHandler) resultHandler).getResultList());
            }
        } finally {
            // 无论是否异常，最后都要关闭 ResultSet，防止资源泄漏（issue #228）
            closeResultSet(rsw.getResultSet());
        }
    }

    /**
     * 处理结果集的每一行，将其映射为对象并交给结果处理器。
     *
     * @param rsw           包装后的结果集对象
     * @param resultMap     当前要使用的结果映射
     * @param resultHandler 结果处理器（用于收集或处理结果）
     * @param rowBounds     分页参数（如偏移量和限制）
     * @param parentMapping 父级映射（嵌套映射时用，普通查询为null）
     * @throws SQLException SQL异常
     */
    public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
        // todo:源码这里会根据 resultMap 是否有嵌套映射调用不同的方法，当前简化处理，直接调用非嵌套映射的方法。
        handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    }

    /**
     * 处理简单 ResultMap（无嵌套映射）对应的结果集每一行，将每行数据映射为对象并交给结果处理器。
     *
     * @param rsw           包装后的结果集对象
     * @param resultMap     当前要使用的结果映射
     * @param resultHandler 结果处理器（用于收集或处理结果）
     * @param rowBounds     分页参数（如偏移量和限制）
     * @param parentMapping 父级映射（嵌套映射时用，普通查询为null）
     * @throws SQLException SQL异常
     */
    private void handleRowValuesForSimpleResultMap(
            ResultSetWrapper rsw,
            ResultMap resultMap,
            ResultHandler<?> resultHandler,
            RowBounds rowBounds,
            ResultMapping parentMapping
    ) throws SQLException {
        // 创建一个用于存储当前处理结果的上下文对象
        DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
        // 获取原始的 JDBC 结果集对象
        ResultSet resultSet = rsw.getResultSet();
        // 根据 rowBounds 跳过指定数量的行，实现分页
        skipRows(resultSet, rowBounds);
        // 循环处理每一行数据，直到达到分页限制、结果集关闭或没有更多数据
        while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
            // 将当前行的数据映射为 Java 对象
            Object rowValue = getRowValue(rsw, resultMap, null);
            // 将映射得到的对象交给结果处理器（如收集到 List 或自定义处理）
            storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
        }
    }

    /**
     * 跳过结果集中的指定行数，实现分页的偏移功能。
     * TODO:分页参数 RowBounds 对象主要用于该方法。
     *
     * @param rs        JDBC的ResultSet对象，表示查询结果集
     * @param rowBounds RowBounds对象，包含分页的偏移量(offset)和限制(limit)
     * @throws SQLException SQL异常
     */
    private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {
        // 判断结果集类型是否支持绝对定位（不是仅向前遍历类型）
        if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
            // 如果需要跳过的行数大于0
            if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {
                // 直接使用absolute方法跳转到指定的行（偏移量）
                rs.absolute(rowBounds.getOffset());
            }
        } else {
            // 如果结果集类型只支持向前遍历（如MySQL默认），只能用next()一行一行跳过
            for (int i = 0; i < rowBounds.getOffset(); i++) {
                // 如果已经没有下一行了，提前结束循环
                if (!rs.next()) {
                    break;
                }
            }
        }
    }

    /**
     * 判断是否还需要继续处理更多的结果集行。
     *
     * @param context   当前结果处理的上下文对象，记录了已处理的行数和是否停止处理等信息
     * @param rowBounds 分页参数，包含最大处理行数（limit）等
     * @return 如果还没达到最大行数且没有被标记为停止，则返回true，表示可以继续处理下一行
     */
    private boolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) {
        // 只有在未被停止（isStopped为false）且已处理的行数小于最大限制（limit）时，才继续处理
        return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
    }

    /**
     * 从结果集包装器中获取一行数据，并将其映射为对应的 Java 对象。
     *
     * @param rsw          包装后的结果集对象
     * @param resultMap    当前要使用的结果映射
     * @param columnPrefix 列名前缀（用于区分多表查询时的同名列）
     * @return 映射后的 Java 对象，如果没有有效数据则返回 null
     * @throws SQLException SQL 异常
     */
    private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
        // 创建结果对象（即将当前行数据映射为 Java 对象）
        Object rowValue = createResultObject(rsw, resultMap, columnPrefix);
        // 如果成功创建了对象，且不是简单类型（如基本类型或有类型处理器的类型）
        if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
            // 用 MetaObject 包装结果对象，方便通过反射操作属性
            final MetaObject metaObject = configuration.newMetaObject(rowValue);
            // 判断是否需要自动映射（如自动将列名和属性名对应）
            if (shouldApplyAutomaticMappings(resultMap, false)) {
                // 自动映射未手动指定的列到属性
                applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
            }
            // TODO:这里再次调用 applyPropertyMappings 方法，处理手动映射的列到属性。
            applyPropertyMappings(rsw, resultMap, metaObject, columnPrefix);
        }
        // 返回最终的结果对象
        return rowValue;
    }

    /**
     * 自动将未手动映射的数据库列映射到 Java 对象属性。
     *
     * @param rsw          包装后的结果集对象
     * @param resultMap    当前要使用的结果映射
     * @param metaObject   结果对象的元数据包装器（用于反射设置属性）
     * @param columnPrefix 列名前缀（用于区分多表查询时的同名列）
     * @return 如果有任何属性被成功赋值，则返回 true，否则返回 false
     * @throws SQLException SQL 异常
     */
    private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
        // 获取所有未手动映射的列与属性的自动映射关系
        List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
        // 标记是否有属性被成功赋值
        boolean foundValues = false;
        // 如果存在自动映射关系
        if (!autoMapping.isEmpty()) {
            // 遍历每一个自动映射关系
            for (UnMappedColumnAutoMapping mapping : autoMapping) {
                // 从结果集中获取当前列的值，使用对应的类型处理器。TODO:主要在这里使用类型处理器 TypeHandler 从结果集中获取值。
                final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
                // 如果值不为 null，说明找到了有效数据
                if (value != null) {
                    foundValues = true;
                }
                // 如果值不为 null，或者配置了允许对 null 调用 setter 方法，且对应属性不是基本类型
                if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
                    // 允许对 null 调用 setter（即使没有查到数据也会设置属性为 null）
                    metaObject.setValue(mapping.property, value);
                }
            }
        }
        // 返回是否有属性被成功赋值
        return foundValues;
    }

    /**
     * 将结果集中的列值映射到 Java 对象的属性上。
     * 遍历 resultMap 中所有属性映射（propertyMappings），
     * 依次从结果集获取对应的值，并设置到 metaObject（目标对象）中。
     *
     * @param rsw          结果集包装器，包含列名等信息
     * @param resultMap    当前要使用的结果映射
     * @param metaObject   目标对象的元对象，用于反射设置属性
     * @param columnPrefix 列名前缀（用于区分多表查询时的同名列）
     * @return 是否至少有一个属性成功获取到值
     * @throws SQLException SQL异常
     */
    private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
        // 获取所有已映射的列名（大写），用于后续判断列是否存在
        final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
        // 标记是否至少有一个属性成功获取到值
        boolean foundValues = false;
        // 获取 resultMap 中所有属性映射配置
        final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
        // 遍历每个属性映射
        for (ResultMapping propertyMapping : propertyMappings) {
            // 获取当前属性对应的列名，并加上前缀
            String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
            /**
             * TODO:
             *  1.该 for 循环主要是遍历 resultMap 中的每个属性映射配置（ResultMapping），处理每个属性对应数据库表中的列名。
             *  2.对于每个属性映射，先获取其对应的列名（加上前缀），然后检查该列名是否存在于 {@link ResultSetWrapper#mappedColumnNamesMap} 中对应以 columnPrefix 开头的映射列名列表中。
             *  3.如果存在该列名的映射配置，则处理该属性映射，从结果集中获取该列的值，并设置到目标对象的对应属性中。
             *  4.如果不存在该列名的映射配置，则跳过该属性映射，继续下一个属性映射的处理。
             */
            if (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) {
                // 从结果集中获取该属性的值（可能涉及类型转换或延迟加载）
                Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, columnPrefix);
                // 获取当前属性名
                final String property = propertyMapping.getProperty();
                // 如果属性名为 null，跳过
                if (property == null) {
                    continue;
                }
                // 如果成功获取到值，标记 foundValues 为 true
                if (value != null) {
                    foundValues = true;
                }
                // 如果值不为 null，或者配置了 set null 也调用 setter（且属性不是基本类型），则设置属性值
                if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) {
                    metaObject.setValue(property, value);
                }
            }
        }
        // 返回是否至少有一个属性成功获取到值
        return foundValues;
    }

    /**
     * 获取属性映射对应的值（支持普通列、嵌套查询、嵌套结果集）。
     *
     * @param rs               JDBC 的 ResultSet 对象，表示当前行数据
     * @param metaResultObject 当前正在填充的目标对象的 MetaObject
     * @param propertyMapping  当前属性的映射配置
     * @param columnPrefix     列名前缀（用于区分多表查询时的同名列）
     * @return 属性的值，可能是普通值、延迟加载标记或嵌套查询结果
     * @throws SQLException SQL 异常
     */
    private Object getPropertyMappingValue(
            ResultSet rs,
            MetaObject metaResultObject,
            ResultMapping propertyMapping,
            String columnPrefix
    ) throws SQLException {
        // todo:源码这里还会处理嵌套查询和嵌套结果集的情况，当前简化处理，直接处理普通属性映射。
        // 普通属性映射，直接通过类型处理器从结果集中获取值
        final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
        // 拼接列名前缀，得到实际的数据库列名
        final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
        // 使用类型处理器从结果集中获取该列的值，并返回
        return typeHandler.getResult(rs, column);
    }

    /**
     * 为列名添加前缀（通常用于多表查询时区分不同表的同名列）。
     * 如果列名或前缀为空，则直接返回原始列名，否则返回“前缀+列名”。
     *
     * @param columnName 列名
     * @param prefix     前缀
     * @return 加上前缀后的列名
     */
    private String prependPrefix(String columnName, String prefix) {
        // 如果列名为null或空，或者前缀为null或空，则直接返回原始列名
        if (columnName == null || columnName.length() == 0 || prefix == null || prefix.length() == 0) {
            return columnName;
        }
        // 否则返回前缀和列名拼接后的字符串
        return prefix + columnName;
    }

    /**
     * 判断是否应该对结果集应用自动映射（automatic mapping）。
     * 自动映射是指：当数据库查询结果的列名和 Java 对象的属性名一致时，自动将列值赋给属性，无需手动配置映射关系。
     *
     * @param resultMap 当前的 ResultMap（结果映射配置）
     * @param isNested  是否为嵌套映射（true 表示当前在处理嵌套的结果映射），todo:暂时不处理嵌套映射，第二参数默认传 false。
     * @return 如果应该自动映射，返回 true；否则返回 false
     */
    private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {
        // 如果 ResultMap 显式指定了 autoMapping 属性（即手动配置了是否自动映射）
        if (resultMap.getAutoMapping() != null) {
            // 按照 ResultMap 的配置返回（true 或 false）
            return resultMap.getAutoMapping();
        } else {
            // 如果没有显式指定，分两种情况判断
            if (isNested) {
                // 如果是嵌套映射，只有全局配置为 FULL 时才自动映射
                return false;
            } else {
                // 如果不是嵌套映射，只要全局配置不是 NONE，就自动映射
                return true;
            }
        }
    }

    /**
     * 存储结果对象到结果处理器或与父对象关联
     *
     * @param resultHandler 结果处理器（用于收集或处理结果）
     * @param resultContext 当前结果处理的上下文对象
     * @param rowValue      当前行映射得到的对象
     * @param parentMapping 父级映射（嵌套映射时用，普通查询为null）
     * @param rs            JDBC结果集对象
     * @throws SQLException SQL异常
     */
    private void storeObject(
            ResultHandler<?> resultHandler,
            DefaultResultContext<Object> resultContext,
            Object rowValue,
            ResultMapping parentMapping,
            ResultSet rs
    ) throws SQLException {
        if (parentMapping != null) {
            // todo:嵌套映射的处理逻辑，目前简化处理，未实现，待完善。
        } else {
            // 如果没有父级映射，说明是普通查询，直接交给结果处理器处理
            callResultHandler(resultHandler, resultContext, rowValue);
        }
    }

    /**
     * 调用结果处理器处理当前行的结果对象。
     *
     * @param resultHandler 结果处理器
     * @param resultContext 当前结果处理的上下文对象
     * @param rowValue      当前行映射得到的对象
     */
    private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {
        // 将当前行的结果对象添加到结果上下文中
        resultContext.nextResultObject(rowValue);
        // 调用结果处理器的 handleResult 方法处理当前结果对象
        // 这里强制类型转换为 ResultHandler<Object>，因为泛型信息在运行时会被擦除
        ((ResultHandler<Object>) resultHandler).handleResult(resultContext);
    }

    /**
     * 创建结果对象（即将当前行数据映射为 Java 对象）。
     * 该方法会根据 ResultMap 的配置，决定是用无参构造方法、带参构造方法还是工厂方法来实例化对象。
     * 同时会处理延迟加载（懒加载）相关的代理对象。
     *
     * @param rsw          包装后的结果集对象
     * @param resultMap    当前要使用的结果映射
     * @param columnPrefix 列名前缀（用于区分多表查询时的同名列）
     * @return 映射后的 Java 对象，如果没有有效数据则返回 null
     * @throws SQLException SQL 异常
     */
    private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
        // 创建两个列表，分别用于存储构造方法的参数类型和参数值
        final List<Class<?>> constructorArgTypes = new ArrayList<>();
        final List<Object> constructorArgs = new ArrayList<>();

        // 调用重载方法，尝试根据 ResultMap 配置和当前行数据创建结果对象
        Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
        // 如果成功创建了对象，且不是简单类型（如基本类型或有类型处理器的类型）
        if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
            // todo:源码这里存在其他处理逻辑，比如处理嵌套结果集和延迟加载代理，当前简化处理，暂不实现这些逻辑。
        }

        // 返回最终创建的结果对象
        return resultObject;
    }

    /**
     * 根据 ResultMap 和当前行数据，创建一个结果对象实例。
     * 该方法会根据不同情况选择合适的方式实例化对象（如基本类型、带参构造、无参构造等）。
     *
     * @param rsw                 包装后的结果集对象
     * @param resultMap           当前要使用的结果映射
     * @param constructorArgTypes 构造方法参数类型列表（用于记录参数类型）
     * @param constructorArgs     构造方法参数值列表（用于记录参数值）
     * @param columnPrefix        列名前缀（用于区分多表查询时的同名列）
     * @return 创建的结果对象实例
     * @throws SQLException SQL异常
     */
    private Object createResultObject(
            ResultSetWrapper rsw,
            ResultMap resultMap,
            List<Class<?>> constructorArgTypes,
            List<Object> constructorArgs,
            String columnPrefix
    ) throws SQLException {
        // 获取结果类型的Class对象
        final Class<?> resultType = resultMap.getType();
        // 获取该类型的MetaClass（用于反射操作）
        final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
        // 获取所有构造方法参数的映射配置
        final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
        // 根据不同情况创建结果对象实例
        if (hasTypeHandlerForResultObject(rsw, resultType)) {
            // 1. 如果该类型有对应的TypeHandler（如基本类型或单列映射），直接用TypeHandler创建对象
            return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
        } else if (!constructorMappings.isEmpty()) {
            // 2. 如果ResultMap中配置了构造方法参数映射，则用带参构造方法创建对象
            return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
        } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
            // 3. 如果是接口类型或有无参构造方法，直接用对象工厂创建实例
            return objectFactory.create(resultType);
        } else if (shouldApplyAutomaticMappings(resultMap, false)) {
            // 4. 如果允许自动映射，尝试通过构造方法签名自动推断并创建对象
            return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs);
        }
        // 5. 以上都不满足，抛出异常，表示无法创建该类型的实例
        throw new RuntimeException("Do not know how to create an instance of " + resultType);
    }

    /**
     * 根据构造方法参数映射，使用带参构造方法创建结果对象实例。
     *
     * @param rsw                 结果集包装器，包含当前行数据
     * @param resultType          目标对象的类型
     * @param constructorMappings 构造方法参数的映射配置列表
     * @param constructorArgTypes 构造方法参数类型列表（输出参数）
     * @param constructorArgs     构造方法参数值列表（输出参数）
     * @param columnPrefix        列名前缀（用于区分多表查询时的同名列）
     * @return 创建的结果对象，如果没有有效数据则返回 null
     */
    Object createParameterizedResultObject(
            ResultSetWrapper rsw,
            Class<?> resultType,
            List<ResultMapping> constructorMappings,
            List<Class<?>> constructorArgTypes,
            List<Object> constructorArgs,
            String columnPrefix
    ) {
        // 标记是否至少有一个参数有值
        boolean foundValues = false;
        // 遍历每一个构造方法参数的映射配置
        for (ResultMapping constructorMapping : constructorMappings) {
            // 获取参数类型
            final Class<?> parameterType = constructorMapping.getJavaType();
            // 获取参数对应的数据库列名
            final String column = constructorMapping.getColumn();
            // 用于存储参数的实际值
            final Object value;
            try {
                // todo:源码这里还会处理嵌套查询和嵌套结果集的情况，当前简化处理，直接处理普通参数映射。
                // 直接通过类型处理器从结果集中获取该列的值
                final TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();
                value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(column, columnPrefix));
            } catch (Exception e) {
                // 如果获取参数值时出错，抛出执行器异常并附带详细信息
                throw new RuntimeException("Could not process result for mapping: " + constructorMapping, e);
            }
            // 记录参数类型
            constructorArgTypes.add(parameterType);
            // 记录参数值
            constructorArgs.add(value);
            // 只要有一个参数有值就标记为 true
            foundValues = value != null || foundValues;
        }
        // 如果至少有一个参数有值，则用对象工厂和参数列表创建对象，否则返回 null
        return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
    }

    /**
     * 尝试通过构造方法签名自动推断并创建结果对象实例。
     * 该方法会优先使用无参构造方法，如果没有，则尝试匹配参数类型与JDBC类型兼容的构造方法。
     *
     * @param rsw                 结果集包装器，包含当前行数据和JDBC类型信息
     * @param resultType          目标对象的类型
     * @param constructorArgTypes 构造方法参数类型列表（输出参数）
     * @param constructorArgs     构造方法参数值列表（输出参数）
     * @return 创建的结果对象实例
     * @throws SQLException SQL异常
     */
    private Object createByConstructorSignature(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) throws SQLException {
        // 获取目标类型的所有构造方法
        final Constructor<?>[] constructors = resultType.getDeclaredConstructors();
        // 查找无参构造方法
        final Constructor<?> defaultConstructor = findDefaultConstructor(constructors);
        if (defaultConstructor != null) {
            // 如果有无参构造方法，优先使用它创建对象
            return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, defaultConstructor);
        } else {
            // 如果没有无参构造方法，遍历所有构造方法
            for (Constructor<?> constructor : constructors) {
                // 检查该构造方法的参数类型是否和JDBC类型兼容
                if (allowedConstructorUsingTypeHandlers(constructor, rsw.getJdbcTypes())) {
                    // 如果兼容，使用该构造方法创建对象
                    return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, constructor);
                }
            }
        }
        // 如果没有找到合适的构造方法，抛出异常
        throw new RuntimeException("No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames());
    }

    /**
     * 查找默认构造方法（无参构造方法或带有 @AutomapConstructor 注解的构造方法）。
     * 该方法用于自动映射对象时，优先选择合适的构造方法进行实例化。
     *
     * @param constructors 构造方法数组（通过反射获取的所有构造方法）
     * @return 找到的默认构造方法，如果没有则返回 null
     */
    private Constructor<?> findDefaultConstructor(final Constructor<?>[] constructors) {
        // 如果只有一个构造方法，直接返回它（无论是否有参数）
        if (constructors.length == 1) {
            return constructors[0];
        }

        // 遍历所有构造方法
        for (final Constructor<?> constructor : constructors) {
            // todo:源码这里还存在解析 @AutomapConstructor 注解，获取带有该注解的构造方法，暂不实现
        }
        // 如果没有找到合适的构造方法，则返回 null
        return null;
    }

    /**
     * 使用指定的构造方法，通过反射创建结果对象实例。
     * 该方法会根据构造方法参数类型，从结果集中依次取出对应的列值，组装参数列表，然后调用构造方法实例化对象。
     *
     * @param rsw                 结果集包装器，包含当前行数据和列名等信息
     * @param resultType          目标对象的类型
     * @param constructorArgTypes 构造方法参数类型列表（输出参数）
     * @param constructorArgs     构造方法参数值列表（输出参数）
     * @param constructor         要使用的构造方法
     * @return 创建的结果对象，如果没有有效数据则返回 null
     * @throws SQLException SQL异常
     */
    private Object createUsingConstructor(
            ResultSetWrapper rsw,
            Class<?> resultType,
            List<Class<?>> constructorArgTypes,
            List<Object> constructorArgs,
            Constructor<?> constructor
    ) throws SQLException {
        // 标记是否至少有一个参数有值
        boolean foundValues = false;
        // 遍历构造方法的每一个参数
        for (int i = 0; i < constructor.getParameterTypes().length; i++) {
            // 获取第i个参数的类型
            Class<?> parameterType = constructor.getParameterTypes()[i];
            // 获取第i个参数对应的列名
            String columnName = rsw.getColumnNames().get(i);
            // 获取类型处理器，用于类型转换
            TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName);
            // 从结果集中获取该列的值
            Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
            // 记录参数类型
            constructorArgTypes.add(parameterType);
            // 记录参数值
            constructorArgs.add(value);
            // 只要有一个参数有值就标记为true
            foundValues = value != null || foundValues;
        }
        // 如果至少有一个参数有值，则用对象工厂和参数列表创建对象，否则返回null
        return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
    }

    /**
     * 判断指定的构造方法参数类型，是否都能通过类型处理器（TypeHandler）与JDBC类型一一对应。
     * 这用于自动映射数据库结果集到Java对象时，确保每个构造参数都能正确赋值。
     *
     * @param constructor 需要检查的构造方法
     * @param jdbcTypes   数据库结果集每一列对应的JDBC类型列表
     * @return 如果所有参数类型都能找到合适的TypeHandler，则返回true，否则返回false
     */
    private boolean allowedConstructorUsingTypeHandlers(final Constructor<?> constructor, final List<JdbcType> jdbcTypes) {
        // 获取构造方法的所有参数类型（如int、String等）
        final Class<?>[] parameterTypes = constructor.getParameterTypes();
        // 如果参数个数和JDBC类型个数不一致，说明不能一一对应，直接返回false
        if (parameterTypes.length != jdbcTypes.size()) {
            return false;
        }
        // 遍历每一个参数
        for (int i = 0; i < parameterTypes.length; i++) {
            // 检查当前参数类型和对应的JDBC类型，是否有合适的TypeHandler可以处理
            if (!typeHandlerRegistry.hasTypeHandler(parameterTypes[i], jdbcTypes.get(i))) {
                // 如果没有找到合适的TypeHandler，返回false
                return false;
            }
        }
        // 所有参数类型都能找到TypeHandler，返回true
        return true;
    }

    /**
     * 从结果集包装器中获取一个简单类型（如基本类型、String、Date等）的结果对象。
     * 适用于只查询单列、单值的情况（如 select count(*)、select name from ...）。
     *
     * @param rsw          包装后的结果集对象，包含原始ResultSet及列名、类型等信息
     * @param resultMap    当前要使用的结果映射（包含目标Java类型等信息）
     * @param columnPrefix 列名前缀（用于多表查询时区分同名列）
     * @return 通过类型处理器转换后的Java对象
     * @throws SQLException SQL异常
     */
    private Object createPrimitiveResultObject(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
        // 获取结果映射中配置的目标Java类型
        final Class<?> resultType = resultMap.getType();
        // 用于存放要读取的数据库列名
        final String columnName;
        // 如果ResultMap中有配置ResultMapping（通常是手动指定了列名和属性的映射）
        if (!resultMap.getResultMappings().isEmpty()) {
            // 获取所有ResultMapping配置
            final List<ResultMapping> resultMappingList = resultMap.getResultMappings();
            // 取第一个ResultMapping（只处理单列情况）
            final ResultMapping mapping = resultMappingList.get(0);
            // 拼接列名前缀，得到实际要读取的数据库列名
            columnName = prependPrefix(mapping.getColumn(), columnPrefix);
        } else {
            // 如果没有手动配置映射，直接取结果集的第一个列名
            columnName = rsw.getColumnNames().get(0);
        }
        // 获取该类型和列名对应的类型处理器（负责JDBC类型和Java类型的转换）
        final TypeHandler<?> typeHandler = rsw.getTypeHandler(resultType, columnName);
        // 使用类型处理器从结果集中读取该列的值，并转换为Java对象返回
        return typeHandler.getResult(rsw.getResultSet(), columnName);
    }

    /**
     * 根据未映射的数据库列，自动生成列与 Java 属性的映射关系。
     *
     * @param rsw          结果集包装器，包含列名、JDBC类型等信息
     * @param resultMap    当前要使用的结果映射
     * @param metaObject   目标 Java 对象的元对象（用于反射操作属性）
     * @param columnPrefix 列名前缀（用于区分多表查询时的同名列）
     * @return 自动映射关系的列表
     * @throws SQLException SQL异常
     */
    private List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
        // 生成自动映射缓存的 key，格式为 resultMapId:columnPrefix
        final String mapKey = resultMap.getId() + ":" + columnPrefix;
        // 先从缓存中查找是否已生成过自动映射
        List<UnMappedColumnAutoMapping> autoMapping = autoMappingsCache.get(mapKey);
        if (autoMapping == null) {
            // 如果缓存没有，则新建一个列表用于存放自动映射关系
            autoMapping = new ArrayList<>();
            // 获取所有未被手动映射的数据库列名
            final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
            // 遍历每一个未映射的列
            for (String columnName : unmappedColumnNames) {
                String propertyName = columnName;
                // 如果有列名前缀，且列名以该前缀开头，则去掉前缀得到属性名
                if (columnPrefix != null && !columnPrefix.isEmpty()) {
                    // 当指定了列名前缀时，只处理以该前缀开头的列
                    if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
                        propertyName = columnName.substring(columnPrefix.length());
                    } else {
                        // 如果列名不以前缀开头，跳过该列
                        continue;
                    }
                }
                // 查找与列名对应的 Java 属性名（支持下划线转驼峰）
                final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
                // 如果找到了属性名，且该属性有 setter 方法
                if (property != null && metaObject.hasSetter(property)) {
                    // todo:源码这里存在相关处理逻辑，当前简化处理，暂不实现。
                    // 获取属性的类型
                    final Class<?> propertyType = metaObject.getSetterType(property);
                    // 判断该类型和当前列的 JDBC 类型是否有对应的类型处理器
                    if (typeHandlerRegistry.hasTypeHandler(propertyType, rsw.getJdbcType(columnName))) {
                        // 获取类型处理器
                        final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
                        // 添加自动映射关系到列表
                        autoMapping.add(new UnMappedColumnAutoMapping(columnName, property, typeHandler, propertyType.isPrimitive()));
                    } else {
                        // 如果没有合适的类型处理器，执行配置的未知列处理行为
                        // todo:源码存在相关处理逻辑，当前简化处理，暂不实现。
                    }
                } else {
                    // 如果找不到属性名或没有 setter，执行未知列处理行为
                    // todo:源码存在相关处理逻辑，当前简化处理，暂不实现。
                }
            }
            // 将生成的自动映射关系缓存起来，提升下次性能
            autoMappingsCache.put(mapKey, autoMapping);
        }
        // 返回自动映射关系列表
        return autoMapping;
    }

    /**
     * 安全关闭 JDBC 的 ResultSet（结果集）对象，避免资源泄漏。
     * 即使关闭时发生异常也不会抛出，保证调用方不会因关闭失败而出错。
     *
     * @param rs 需要关闭的 ResultSet 对象，可以为 null
     */
    private void closeResultSet(ResultSet rs) {
        try {
            // 如果结果集对象不为 null，则尝试关闭它
            if (rs != null) {
                // 关闭数据库结果集，释放数据库资源
                rs.close();
            }
        } catch (SQLException e) {
            // 如果关闭过程中发生 SQL 异常，这里选择忽略，不做任何处理
        }
    }

    private void validateResultMapsCount(ResultSetWrapper rsw, int resultMapCount) {
        if (rsw != null && resultMapCount < 1) {
            throw new RuntimeException("A query was run and no Result Maps were found for the Mapped Statement '" + mappedStatement.getId()
                    + "'.  It's likely that neither a Result Type nor a Result Map was specified.");
        }
    }

    /**
     * 判断给定的结果类型（resultType）是否有对应的类型处理器（TypeHandler）。
     * 类型处理器用于将数据库中的数据类型和Java类型进行转换。
     *
     * @param rsw        结果集包装器，包含列名和JDBC类型等信息
     * @param resultType 需要判断的Java结果类型
     * @return 如果有对应的类型处理器，返回true，否则返回false
     */
    private boolean hasTypeHandlerForResultObject(ResultSetWrapper rsw, Class<?> resultType) {
        // 如果结果集只有一列
        if (rsw.getColumnNames().size() == 1) {
            // 检查是否有针对该Java类型和该列JDBC类型的TypeHandler
            return typeHandlerRegistry.hasTypeHandler(resultType, rsw.getJdbcType(rsw.getColumnNames().get(0)));
        }
        // 否则，只检查是否有针对该Java类型的TypeHandler
        return typeHandlerRegistry.hasTypeHandler(resultType);
    }
}
